package com.lifeng.mynetty.client;

import com.lifeng.mynetty.client.handler.HttpPostClientHandler;
import com.lifeng.mynetty.common.Client;
import com.lifeng.mynetty.constants.MyNettyContants;
import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelMetadata;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.*;
import io.netty.util.AttributeKey;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.util.Map;

/**
 * Created by lifeng
 * 2017/9/4 15:42
 */
public class HttpPostClient implements Client {
    private static Logger logger = LoggerFactory.getLogger(HttpPostClient.class);
    //字符编码
    private String url;
    private String charset = "utf-8";
    private Bootstrap bootstrap;
    private String contentType = "text/html";
    private String ip;
    private int port;
    private URI uri;
    public void start() throws Exception {
        // 解析URL
        try {
            uri = new URI(url);
            String scheme = uri.getScheme() == null ? "http" : uri.getScheme();
            ip = uri.getHost();
            port = -1;
            if (uri.getPort() == -1) {
                if ("http".equalsIgnoreCase(scheme)) {
                    port = 80;
                } else if ("https".equalsIgnoreCase(scheme)) {
                    port = 443;
                } else {
                    port = -1;
                }
            } else {
                port = uri.getPort();
            }
        } catch (URISyntaxException e) {
            throw new Exception("解析URL出错", e);
        }

        NioEventLoopGroup group = new NioEventLoopGroup();
        try{
            bootstrap = new Bootstrap();
            bootstrap.group(group);
            bootstrap.channel(NioSocketChannel.class);
            bootstrap.handler(new ChannelInitializer<Channel>() {
                @Override
                protected void initChannel(Channel ch) throws Exception {
                    ChannelPipeline pipeline = ch.pipeline();
                    pipeline.addLast("encode", new HttpRequestEncoder());
                    pipeline.addLast("decode", new HttpResponseDecoder());
                    pipeline.addLast("handler", new HttpPostClientHandler(charset));
                }
            });
        }catch (Exception e){
            throw e;
        }finally {
            //group.shutdownGracefully();
        }

    }
    @Override
    public void send(byte[] msg) throws Exception {
        send(null,msg);
    }

    @Override
    public void send(String msgId, byte[] msg) throws Exception {
        Channel channel = bootstrap.connect(ip, port).sync().channel();
        DefaultFullHttpRequest request = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.GET,
                uri.toASCIIString(), Unpooled.wrappedBuffer(msg));
        try {
            request.headers().set(HttpHeaders.Names.HOST, ip);
            request.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.CLOSE);
            request.headers().add(HttpHeaders.Names.CONTENT_TYPE, contentType+"; charset="+charset);
            request.headers().add(HttpHeaders.Names.CONTENT_LENGTH, msg.length);
            logger.debug("Uri >> ", request.uri());
            if (logger.isDebugEnabled()) {
                for (Map.Entry entry : request.headers().entries()) {
                    logger.debug("Http Header >> ", entry.getKey(), ":", entry.getValue());
                }
            }
            logger.debug("Http Body >> " + Unpooled.wrappedBuffer(msg).toString(Charset.forName(charset)));
        } catch (Throwable e) {
            throw new Exception("创建http request出错", e);
        }
        //为了回填响应消息
        if(msgId != null && !"".equals(msgId)){
            channel.attr(AttributeKey.newInstance(MyNettyContants.MSG_KEY)).set(msgId);
        }
        channel.write(request);
        channel.flush();
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getCharset() {
        return charset;
    }

    public void setCharset(String charset) {
        this.charset = charset;
    }

    public String getContentType() {
        return contentType;
    }

    public void setContentType(String contentType) {
        this.contentType = contentType;
    }
}
